#ifndef THINK_THINK_PROCESS_H
#define THINK_THINK_PROCESS_H

static char* think_process =
	"\n"
	"// +----------------------------------------------------------------------\n"
	"// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n"
	"// +----------------------------------------------------------------------\n"
	"// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n"
	"// +----------------------------------------------------------------------\n"
	"// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n"
	"// +----------------------------------------------------------------------\n"
	"// | Author: yunwuxin <448901948@qq.com>\n"
	"// +----------------------------------------------------------------------\n"
	"\n"
	"namespace think;\n"
	"\n"
	"use think\\process\\exception\\Failed as ProcessFailedException;\n"
	"use think\\process\\exception\\Timeout as ProcessTimeoutException;\n"
	"use think\\process\\pipes\\Pipes;\n"
	"use think\\process\\pipes\\Unix as UnixPipes;\n"
	"use think\\process\\pipes\\Windows as WindowsPipes;\n"
	"use think\\process\\Utils;\n"
	"\n"
	"class Process\n"
	"{\n"
	"\n"
	"    const ERR = \'err\';\n"
	"    const OUT = \'out\';\n"
	"\n"
	"    const STATUS_READY      = \'ready\';\n"
	"    const STATUS_STARTED    = \'started\';\n"
	"    const STATUS_TERMINATED = \'terminated\';\n"
	"\n"
	"    const STDIN  = 0;\n"
	"    const STDOUT = 1;\n"
	"    const STDERR = 2;\n"
	"\n"
	"    const TIMEOUT_PRECISION = 0.2;\n"
	"\n"
	"    private $callback;\n"
	"    private $commandline;\n"
	"    private $cwd;\n"
	"    private $env;\n"
	"    private $input;\n"
	"    private $starttime;\n"
	"    private $lastOutputTime;\n"
	"    private $timeout;\n"
	"    private $idleTimeout;\n"
	"    private $options;\n"
	"    private $exitcode;\n"
	"    private $fallbackExitcode;\n"
	"    private $processInformation;\n"
	"    private $outputDisabled = false;\n"
	"    private $stdout;\n"
	"    private $stderr;\n"
	"    private $enhanceWindowsCompatibility = true;\n"
	"    private $enhanceSigchildCompatibility;\n"
	"    private $process;\n"
	"    private $status                       = self::STATUS_READY;\n"
	"    private $incrementalOutputOffset      = 0;\n"
	"    private $incrementalErrorOutputOffset = 0;\n"
	"    private $tty;\n"
	"    private $pty;\n"
	"\n"
	"    private $useFileHandles = false;\n"
	"\n"
	"    /** @var Pipes */\n"
	"    private $processPipes;\n"
	"\n"
	"    private $latestSignal;\n"
	"\n"
	"    private static $sigchild;\n"
	"\n"
	"    /**\n"
	"     * @var array\n"
	"     */\n"
	"    public static $exitCodes = [\n"
	"        0   => \'OK\',\n"
	"        1   => \'General error\',\n"
	"        2   => \'Misuse of shell builtins\',\n"
	"        126 => \'Invoked command cannot execute\',\n"
	"        127 => \'Command not found\',\n"
	"        128 => \'Invalid exit argument\',\n"
	"        // signals\n"
	"        129 => \'Hangup\',\n"
	"        130 => \'Interrupt\',\n"
	"        131 => \'Quit and dump core\',\n"
	"        132 => \'Illegal instruction\',\n"
	"        133 => \'Trace/breakpoint trap\',\n"
	"        134 => \'Process aborted\',\n"
	"        135 => \'Bus error: \"access to undefined portion of memory object\"\',\n"
	"        136 => \'Floating point exception: \"erroneous arithmetic operation\"\',\n"
	"        137 => \'Kill (terminate immediately)\',\n"
	"        138 => \'User-defined 1\',\n"
	"        139 => \'Segmentation violation\',\n"
	"        140 => \'User-defined 2\',\n"
	"        141 => \'Write to pipe with no one reading\',\n"
	"        142 => \'Signal raised by alarm\',\n"
	"        143 => \'Termination (request to terminate)\',\n"
	"        // 144 - not defined\n"
	"        145 => \'Child process terminated, stopped (or continued*)\',\n"
	"        146 => \'Continue if stopped\',\n"
	"        147 => \'Stop executing temporarily\',\n"
	"        148 => \'Terminal stop signal\',\n"
	"        149 => \'Background process attempting to read from tty (\"in\")\',\n"
	"        150 => \'Background process attempting to write to tty (\"out\")\',\n"
	"        151 => \'Urgent data available on socket\',\n"
	"        152 => \'CPU time limit exceeded\',\n"
	"        153 => \'File size limit exceeded\',\n"
	"        154 => \'Signal raised by timer counting virtual time: \"virtual timer expired\"\',\n"
	"        155 => \'Profiling timer expired\',\n"
	"        // 156 - not defined\n"
	"        157 => \'Pollable event\',\n"
	"        // 158 - not defined\n"
	"        159 => \'Bad syscall\',\n"
	"    ];\n"
	"\n"
	"    /**\n"
	"     * 构造方法\n"
	"     * @param string         $commandline 指令\n"
	"     * @param string|null    $cwd         工作目录\n"
	"     * @param array|null     $env         环境变量\n"
	"     * @param string|null    $input       输入\n"
	"     * @param int|float|null $timeout     超时时间\n"
	"     * @param array          $options     proc_open的选项\n"
	"     * @throws \\RuntimeException\n"
	"     * @api\n"
	"     */\n"
	"    public function __construct($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = [])\n"
	"    {\n"
	"        if (!function_exists(\'proc_open\')) {\n"
	"            throw new \\RuntimeException(\'The Process class relies on proc_open, which is not available on your PHP installation.\');\n"
	"        }\n"
	"\n"
	"        $this->commandline = $commandline;\n"
	"        $this->cwd         = $cwd;\n"
	"\n"
	"        if (null === $this->cwd && (defined(\'ZEND_THREAD_SAFE\') || \'\\\\\' === DS)) {\n"
	"            $this->cwd = getcwd();\n"
	"        }\n"
	"        if (null !== $env) {\n"
	"            $this->setEnv($env);\n"
	"        }\n"
	"\n"
	"        $this->input = $input;\n"
	"        $this->setTimeout($timeout);\n"
	"        $this->useFileHandles               = \'\\\\\' === DS;\n"
	"        $this->pty                          = false;\n"
	"        $this->enhanceWindowsCompatibility  = true;\n"
	"        $this->enhanceSigchildCompatibility = \'\\\\\' !== DS && $this->isSigchildEnabled();\n"
	"        $this->options                      = array_replace([\n"
	"            \'suppress_errors\' => true,\n"
	"            \'binary_pipes\'    => true,\n"
	"        ], $options);\n"
	"    }\n"
	"\n"
	"    public function __destruct()\n"
	"    {\n"
	"        $this->stop();\n"
	"    }\n"
	"\n"
	"    public function __clone()\n"
	"    {\n"
	"        $this->resetProcessData();\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 运行指令\n"
	"     * @param callback|null $callback\n"
	"     * @return int\n"
	"     */\n"
	"    public function run($callback = null)\n"
	"    {\n"
	"        $this->start($callback);\n"
	"\n"
	"        return $this->wait();\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 运行指令\n"
	"     * @param callable|null $callback\n"
	"     * @return self\n"
	"     * @throws \\RuntimeException\n"
	"     * @throws ProcessFailedException\n"
	"     */\n"
	"    public function mustRun($callback = null)\n"
	"    {\n"
	"        if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) {\n"
	"            throw new \\RuntimeException(\'This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.\');\n"
	"        }\n"
	"\n"
	"        if (0 !== $this->run($callback)) {\n"
	"            throw new ProcessFailedException($this);\n"
	"        }\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 启动进程并写到 STDIN 输入后返回。\n"
	"     * @param callable|null $callback\n"
	"     * @throws \\RuntimeException\n"
	"     * @throws \\RuntimeException\n"
	"     * @throws \\LogicException\n"
	"     */\n"
	"    public function start($callback = null)\n"
	"    {\n"
	"        if ($this->isRunning()) {\n"
	"            throw new \\RuntimeException(\'Process is already running\');\n"
	"        }\n"
	"        if ($this->outputDisabled && null !== $callback) {\n"
	"            throw new \\LogicException(\'Output has been disabled, enable it to allow the use of a callback.\');\n"
	"        }\n"
	"\n"
	"        $this->resetProcessData();\n"
	"        $this->starttime = $this->lastOutputTime = microtime(true);\n"
	"        $this->callback  = $this->buildCallback($callback);\n"
	"        $descriptors     = $this->getDescriptors();\n"
	"\n"
	"        $commandline = $this->commandline;\n"
	"\n"
	"        if (\'\\\\\' === DS && $this->enhanceWindowsCompatibility) {\n"
	"            $commandline = \'cmd /V:ON /E:ON /C \"(\' . $commandline . \')\';\n"
	"            foreach ($this->processPipes->getFiles() as $offset => $filename) {\n"
	"                $commandline .= \' \' . $offset . \'>\' . Utils::escapeArgument($filename);\n"
	"            }\n"
	"            $commandline .= \'\"\';\n"
	"\n"
	"            if (!isset($this->options[\'bypass_shell\'])) {\n"
	"                $this->options[\'bypass_shell\'] = true;\n"
	"            }\n"
	"        }\n"
	"\n"
	"        $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options);\n"
	"\n"
	"        if (!is_resource($this->process)) {\n"
	"            throw new \\RuntimeException(\'Unable to launch a new process.\');\n"
	"        }\n"
	"        $this->status = self::STATUS_STARTED;\n"
	"\n"
	"        if ($this->tty) {\n"
	"            return;\n"
	"        }\n"
	"\n"
	"        $this->updateStatus(false);\n"
	"        $this->checkTimeout();\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 重启进程\n"
	"     * @param callable|null $callback\n"
	"     * @return Process\n"
	"     * @throws \\RuntimeException\n"
	"     * @throws \\RuntimeException\n"
	"     */\n"
	"    public function restart($callback = null)\n"
	"    {\n"
	"        if ($this->isRunning()) {\n"
	"            throw new \\RuntimeException(\'Process is already running\');\n"
	"        }\n"
	"\n"
	"        $process = clone $this;\n"
	"        $process->start($callback);\n"
	"\n"
	"        return $process;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 等待要终止的进程\n"
	"     * @param callable|null $callback\n"
	"     * @return int\n"
	"     */\n"
	"    public function wait($callback = null)\n"
	"    {\n"
	"        $this->requireProcessIsStarted(__FUNCTION__);\n"
	"\n"
	"        $this->updateStatus(false);\n"
	"        if (null !== $callback) {\n"
	"            $this->callback = $this->buildCallback($callback);\n"
	"        }\n"
	"\n"
	"        do {\n"
	"            $this->checkTimeout();\n"
	"            $running = \'\\\\\' === DS ? $this->isRunning() : $this->processPipes->areOpen();\n"
	"            $close   = \'\\\\\' !== DS || !$running;\n"
	"            $this->readPipes(true, $close);\n"
	"        } while ($running);\n"
	"\n"
	"        while ($this->isRunning()) {\n"
	"            usleep(1000);\n"
	"        }\n"
	"\n"
	"        if ($this->processInformation[\'signaled\'] && $this->processInformation[\'termsig\'] !== $this->latestSignal) {\n"
	"            throw new \\RuntimeException(sprintf(\'The process has been signaled with signal \"%s\".\', $this->processInformation[\'termsig\']));\n"
	"        }\n"
	"\n"
	"        return $this->exitcode;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取PID\n"
	"     * @return int|null\n"
	"     * @throws \\RuntimeException\n"
	"     */\n"
	"    public function getPid()\n"
	"    {\n"
	"        if ($this->isSigchildEnabled()) {\n"
	"            throw new \\RuntimeException(\'This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.\');\n"
	"        }\n"
	"\n"
	"        $this->updateStatus(false);\n"
	"\n"
	"        return $this->isRunning() ? $this->processInformation[\'pid\'] : null;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 将一个 POSIX 信号发送到进程中\n"
	"     * @param int $signal\n"
	"     * @return Process\n"
	"     */\n"
	"    public function signal($signal)\n"
	"    {\n"
	"        $this->doSignal($signal, true);\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 禁用从底层过程获取输出和错误输出。\n"
	"     * @return Process\n"
	"     */\n"
	"    public function disableOutput()\n"
	"    {\n"
	"        if ($this->isRunning()) {\n"
	"            throw new \\RuntimeException(\'Disabling output while the process is running is not possible.\');\n"
	"        }\n"
	"        if (null !== $this->idleTimeout) {\n"
	"            throw new \\LogicException(\'Output can not be disabled while an idle timeout is set.\');\n"
	"        }\n"
	"\n"
	"        $this->outputDisabled = true;\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 开启从底层过程获取输出和错误输出。\n"
	"     * @return Process\n"
	"     * @throws \\RuntimeException\n"
	"     */\n"
	"    public function enableOutput()\n"
	"    {\n"
	"        if ($this->isRunning()) {\n"
	"            throw new \\RuntimeException(\'Enabling output while the process is running is not possible.\');\n"
	"        }\n"
	"\n"
	"        $this->outputDisabled = false;\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 输出是否禁用\n"
	"     * @return bool\n"
	"     */\n"
	"    public function isOutputDisabled()\n"
	"    {\n"
	"        return $this->outputDisabled;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取当前的输出管道\n"
	"     * @return string\n"
	"     * @throws \\LogicException\n"
	"     * @throws \\LogicException\n"
	"     * @api\n"
	"     */\n"
	"    public function getOutput()\n"
	"    {\n"
	"        if ($this->outputDisabled) {\n"
	"            throw new \\LogicException(\'Output has been disabled.\');\n"
	"        }\n"
	"\n"
	"        $this->requireProcessIsStarted(__FUNCTION__);\n"
	"\n"
	"        $this->readPipes(false, \'\\\\\' === DS ? !$this->processInformation[\'running\'] : true);\n"
	"\n"
	"        return $this->stdout;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 以增量方式返回的输出结果。\n"
	"     * @return string\n"
	"     */\n"
	"    public function getIncrementalOutput()\n"
	"    {\n"
	"        $this->requireProcessIsStarted(__FUNCTION__);\n"
	"\n"
	"        $data = $this->getOutput();\n"
	"\n"
	"        $latest = substr($data, $this->incrementalOutputOffset);\n"
	"\n"
	"        if (false === $latest) {\n"
	"            return \'\';\n"
	"        }\n"
	"\n"
	"        $this->incrementalOutputOffset = strlen($data);\n"
	"\n"
	"        return $latest;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 清空输出\n"
	"     * @return Process\n"
	"     */\n"
	"    public function clearOutput()\n"
	"    {\n"
	"        $this->stdout                  = \'\';\n"
	"        $this->incrementalOutputOffset = 0;\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 返回当前的错误输出的过程 (STDERR)。\n"
	"     * @return string\n"
	"     */\n"
	"    public function getErrorOutput()\n"
	"    {\n"
	"        if ($this->outputDisabled) {\n"
	"            throw new \\LogicException(\'Output has been disabled.\');\n"
	"        }\n"
	"\n"
	"        $this->requireProcessIsStarted(__FUNCTION__);\n"
	"\n"
	"        $this->readPipes(false, \'\\\\\' === DS ? !$this->processInformation[\'running\'] : true);\n"
	"\n"
	"        return $this->stderr;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 以增量方式返回 errorOutput\n"
	"     * @return string\n"
	"     */\n"
	"    public function getIncrementalErrorOutput()\n"
	"    {\n"
	"        $this->requireProcessIsStarted(__FUNCTION__);\n"
	"\n"
	"        $data = $this->getErrorOutput();\n"
	"\n"
	"        $latest = substr($data, $this->incrementalErrorOutputOffset);\n"
	"\n"
	"        if (false === $latest) {\n"
	"            return \'\';\n"
	"        }\n"
	"\n"
	"        $this->incrementalErrorOutputOffset = strlen($data);\n"
	"\n"
	"        return $latest;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 清空 errorOutput\n"
	"     * @return Process\n"
	"     */\n"
	"    public function clearErrorOutput()\n"
	"    {\n"
	"        $this->stderr                       = \'\';\n"
	"        $this->incrementalErrorOutputOffset = 0;\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取退出码\n"
	"     * @return null|int\n"
	"     */\n"
	"    public function getExitCode()\n"
	"    {\n"
	"        if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) {\n"
	"            throw new \\RuntimeException(\'This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.\');\n"
	"        }\n"
	"\n"
	"        $this->updateStatus(false);\n"
	"\n"
	"        return $this->exitcode;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取退出文本\n"
	"     * @return null|string\n"
	"     */\n"
	"    public function getExitCodeText()\n"
	"    {\n"
	"        if (null === $exitcode = $this->getExitCode()) {\n"
	"            return;\n"
	"        }\n"
	"\n"
	"        return isset(self::$exitCodes[$exitcode]) ? self::$exitCodes[$exitcode] : \'Unknown error\';\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 检查是否成功\n"
	"     * @return bool\n"
	"     */\n"
	"    public function isSuccessful()\n"
	"    {\n"
	"        return 0 === $this->getExitCode();\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 是否未捕获的信号已被终止子进程\n"
	"     * @return bool\n"
	"     */\n"
	"    public function hasBeenSignaled()\n"
	"    {\n"
	"        $this->requireProcessIsTerminated(__FUNCTION__);\n"
	"\n"
	"        if ($this->isSigchildEnabled()) {\n"
	"            throw new \\RuntimeException(\'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.\');\n"
	"        }\n"
	"\n"
	"        $this->updateStatus(false);\n"
	"\n"
	"        return $this->processInformation[\'signaled\'];\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 返回导致子进程终止其执行的数。\n"
	"     * @return int\n"
	"     */\n"
	"    public function getTermSignal()\n"
	"    {\n"
	"        $this->requireProcessIsTerminated(__FUNCTION__);\n"
	"\n"
	"        if ($this->isSigchildEnabled()) {\n"
	"            throw new \\RuntimeException(\'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.\');\n"
	"        }\n"
	"\n"
	"        $this->updateStatus(false);\n"
	"\n"
	"        return $this->processInformation[\'termsig\'];\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 检查子进程信号是否已停止\n"
	"     * @return bool\n"
	"     */\n"
	"    public function hasBeenStopped()\n"
	"    {\n"
	"        $this->requireProcessIsTerminated(__FUNCTION__);\n"
	"\n"
	"        $this->updateStatus(false);\n"
	"\n"
	"        return $this->processInformation[\'stopped\'];\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 返回导致子进程停止其执行的数。\n"
	"     * @return int\n"
	"     */\n"
	"    public function getStopSignal()\n"
	"    {\n"
	"        $this->requireProcessIsTerminated(__FUNCTION__);\n"
	"\n"
	"        $this->updateStatus(false);\n"
	"\n"
	"        return $this->processInformation[\'stopsig\'];\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 检查是否正在运行\n"
	"     * @return bool\n"
	"     */\n"
	"    public function isRunning()\n"
	"    {\n"
	"        if (self::STATUS_STARTED !== $this->status) {\n"
	"            return false;\n"
	"        }\n"
	"\n"
	"        $this->updateStatus(false);\n"
	"\n"
	"        return $this->processInformation[\'running\'];\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 检查是否已开始\n"
	"     * @return bool\n"
	"     */\n"
	"    public function isStarted()\n"
	"    {\n"
	"        return self::STATUS_READY != $this->status;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 检查是否已终止\n"
	"     * @return bool\n"
	"     */\n"
	"    public function isTerminated()\n"
	"    {\n"
	"        $this->updateStatus(false);\n"
	"\n"
	"        return self::STATUS_TERMINATED == $this->status;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取当前的状态\n"
	"     * @return string\n"
	"     */\n"
	"    public function getStatus()\n"
	"    {\n"
	"        $this->updateStatus(false);\n"
	"\n"
	"        return $this->status;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 终止进程\n"
	"     */\n"
	"    public function stop()\n"
	"    {\n"
	"        if ($this->isRunning()) {\n"
	"            if (\'\\\\\' === DS && !$this->isSigchildEnabled()) {\n"
	"                exec(sprintf(\'taskkill /F /T /PID %d 2>&1\', $this->getPid()), $output, $exitCode);\n"
	"                if ($exitCode > 0) {\n"
	"                    throw new \\RuntimeException(\'Unable to kill the process\');\n"
	"                }\n"
	"            } else {\n"
	"                $pids = preg_split(\'/\\s+/\', `ps -o pid --no-heading --ppid {$this->getPid()}`);\n"
	"                foreach ($pids as $pid) {\n"
	"                    if (is_numeric($pid)) {\n"
	"                        posix_kill($pid, 9);\n"
	"                    }\n"
	"                }\n"
	"            }\n"
	"        }\n"
	"\n"
	"        $this->updateStatus(false);\n"
	"        if ($this->processInformation[\'running\']) {\n"
	"            $this->close();\n"
	"        }\n"
	"\n"
	"        return $this->exitcode;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 添加一行输出\n"
	"     * @param string $line\n"
	"     */\n"
	"    public function addOutput($line)\n"
	"{\n"
	"        $this->lastOutputTime = microtime(true);\n"
	"        $this->stdout .= $line;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 添加一行错误输出\n"
	"     * @param string $line\n"
	"     */\n"
	"    public function addErrorOutput($line)\n"
	"{\n"
	"        $this->lastOutputTime = microtime(true);\n"
	"        $this->stderr .= $line;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取被执行的指令\n"
	"     * @return string\n"
	"     */\n"
	"    public function getCommandLine()\n"
	"{\n"
	"        return $this->commandline;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置指令\n"
	"     * @param string $commandline\n"
	"     * @return self\n"
	"     */\n"
	"    public function setCommandLine($commandline)\n"
	"{\n"
	"        $this->commandline = $commandline;\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取超时时间\n"
	"     * @return float|null\n"
	"     */\n"
	"    public function getTimeout()\n"
	"{\n"
	"        return $this->timeout;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取idle超时时间\n"
	"     * @return float|null\n"
	"     */\n"
	"    public function getIdleTimeout()\n"
	"{\n"
	"        return $this->idleTimeout;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置超时时间\n"
	"     * @param int|float|null $timeout\n"
	"     * @return self\n"
	"     */\n"
	"    public function setTimeout($timeout)\n"
	"{\n"
	"        $this->timeout = $this->validateTimeout($timeout);\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置idle超时时间\n"
	"     * @param int|float|null $timeout\n"
	"     * @return self\n"
	"     */\n"
	"    public function setIdleTimeout($timeout)\n"
	"{\n"
	"        if (null !== $timeout && $this->outputDisabled) {\n"
	"            throw new \\LogicException(\'Idle timeout can not be set while the output is disabled.\');\n"
	"        }\n"
	"\n"
	"        $this->idleTimeout = $this->validateTimeout($timeout);\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置TTY\n"
	"     * @param bool $tty\n"
	"     * @return self\n"
	"     */\n"
	"    public function setTty($tty)\n"
	"{\n"
	"        if (\'\\\\\' === DS && $tty) {\n"
	"            throw new \\RuntimeException(\'TTY mode is not supported on Windows platform.\');\n"
	"        }\n"
	"        if ($tty && (!file_exists(\'/dev/tty\') || !is_readable(\'/dev/tty\'))) {\n"
	"            throw new \\RuntimeException(\'TTY mode requires /dev/tty to be readable.\');\n"
	"        }\n"
	"\n"
	"        $this->tty = (bool) $tty;\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 检查是否是tty模式\n"
	"     * @return bool\n"
	"     */\n"
	"    public function isTty()\n"
	"{\n"
	"        return $this->tty;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置pty模式\n"
	"     * @param bool $bool\n"
	"     * @return self\n"
	"     */\n"
	"    public function setPty($bool)\n"
	"{\n"
	"        $this->pty = (bool) $bool;\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 是否是pty模式\n"
	"     * @return bool\n"
	"     */\n"
	"    public function isPty()\n"
	"{\n"
	"        return $this->pty;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取工作目录\n"
	"     * @return string|null\n"
	"     */\n"
	"    public function getWorkingDirectory()\n"
	"{\n"
	"        if (null === $this->cwd) {\n"
	"            return getcwd() ?: null;\n"
	"        }\n"
	"\n"
	"        return $this->cwd;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置工作目录\n"
	"     * @param string $cwd\n"
	"     * @return self\n"
	"     */\n"
	"    public function setWorkingDirectory($cwd)\n"
	"{\n"
	"        $this->cwd = $cwd;\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取环境变量\n"
	"     * @return array\n"
	"     */\n"
	"    public function getEnv()\n"
	"{\n"
	"        return $this->env;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置环境变量\n"
	"     * @param array $env\n"
	"     * @return self\n"
	"     */\n"
	"    public function setEnv(array $env)\n"
	"{\n"
	"        $env = array_filter($env, function ($value) {\n"
	"            return !is_array($value);\n"
	"        });\n"
	"\n"
	"        $this->env = [];\n"
	"        foreach ($env as $key => $value) {\n"
	"            $this->env[(binary) $key] = (binary) $value;\n"
	"        }\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取输入\n"
	"     * @return null|string\n"
	"     */\n"
	"    public function getInput()\n"
	"{\n"
	"        return $this->input;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置输入\n"
	"     * @param mixed $input\n"
	"     * @return self\n"
	"     */\n"
	"    public function setInput($input)\n"
	"{\n"
	"        if ($this->isRunning()) {\n"
	"            throw new \\LogicException(\'Input can not be set while the process is running.\');\n"
	"        }\n"
	"\n"
	"        $this->input = Utils::validateInput(sprintf(\'%s::%s\', __CLASS__, __FUNCTION__), $input);\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取proc_open的选项\n"
	"     * @return array\n"
	"     */\n"
	"    public function getOptions()\n"
	"{\n"
	"        return $this->options;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置proc_open的选项\n"
	"     * @param array $options\n"
	"     * @return self\n"
	"     */\n"
	"    public function setOptions(array $options)\n"
	"{\n"
	"        $this->options = $options;\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 是否兼容windows\n"
	"     * @return bool\n"
	"     */\n"
	"    public function getEnhanceWindowsCompatibility()\n"
	"{\n"
	"        return $this->enhanceWindowsCompatibility;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置是否兼容windows\n"
	"     * @param bool $enhance\n"
	"     * @return self\n"
	"     */\n"
	"    public function setEnhanceWindowsCompatibility($enhance)\n"
	"{\n"
	"        $this->enhanceWindowsCompatibility = (bool) $enhance;\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 返回是否 sigchild 兼容模式激活\n"
	"     * @return bool\n"
	"     */\n"
	"    public function getEnhanceSigchildCompatibility()\n"
	"{\n"
	"        return $this->enhanceSigchildCompatibility;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 激活 sigchild 兼容性模式。\n"
	"     * @param bool $enhance\n"
	"     * @return self\n"
	"     */\n"
	"    public function setEnhanceSigchildCompatibility($enhance)\n"
	"{\n"
	"        $this->enhanceSigchildCompatibility = (bool) $enhance;\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 是否超时\n"
	"     */\n"
	"    public function checkTimeout()\n"
	"{\n"
	"        if (self::STATUS_STARTED !== $this->status) {\n"
	"            return;\n"
	"        }\n"
	"\n"
	"        if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {\n"
	"            $this->stop();\n"
	"\n"
	"            throw new ProcessTimeoutException($this, ProcessTimeoutException::TYPE_GENERAL);\n"
	"        }\n"
	"\n"
	"        if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {\n"
	"            $this->stop();\n"
	"\n"
	"            throw new ProcessTimeoutException($this, ProcessTimeoutException::TYPE_IDLE);\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 是否支持pty\n"
	"     * @return bool\n"
	"     */\n"
	"    public static function isPtySupported()\n"
	"{\n"
	"        static $result;\n"
	"\n"
	"        if (null !== $result) {\n"
	"            return $result;\n"
	"        }\n"
	"\n"
	"        if (\'\\\\\' === DS) {\n"
	"            return $result = false;\n"
	"        }\n"
	"\n"
	"        $proc = @proc_open(\'echo 1\', [[\'pty\'], [\'pty\'], [\'pty\']], $pipes);\n"
	"        if (is_resource($proc)) {\n"
	"            proc_close($proc);\n"
	"\n"
	"            return $result = true;\n"
	"        }\n"
	"\n"
	"        return $result = false;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 创建所需的 proc_open 的描述符\n"
	"     * @return array\n"
	"     */\n"
	"    private function getDescriptors()\n"
	"{\n"
	"        if (\'\\\\\' === DS) {\n"
	"            $this->processPipes = WindowsPipes::create($this, $this->input);\n"
	"        } else {\n"
	"            $this->processPipes = UnixPipes::create($this, $this->input);\n"
	"        }\n"
	"        $descriptors = $this->processPipes->getDescriptors($this->outputDisabled);\n"
	"\n"
	"        if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {\n"
	"\n"
	"            $descriptors = array_merge($descriptors, [[\'pipe\', \'w\']]);\n"
	"\n"
	"            $this->commandline = \'(\' . $this->commandline . \') 3>/dev/null; code=$?; echo $code >&3; exit $code\';\n"
	"        }\n"
	"\n"
	"        return $descriptors;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 建立 wait () 使用的回调。\n"
	"     * @param callable|null $callback\n"
	"     * @return callable\n"
	"     */\n"
	"    protected function buildCallback($callback)\n"
	"{\n"
	"        $out      = self::OUT;\n"
	"        $callback = function ($type, $data) use ($callback, $out) {\n"
	"            if ($out == $type) {\n"
	"                $this->addOutput($data);\n"
	"            } else {\n"
	"                $this->addErrorOutput($data);\n"
	"            }\n"
	"\n"
	"            if (null !== $callback) {\n"
	"                call_user_func($callback, $type, $data);\n"
	"            }\n"
	"        };\n"
	"\n"
	"        return $callback;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 更新状态\n"
	"     * @param bool $blocking\n"
	"     */\n"
	"    protected function updateStatus($blocking)\n"
	"{\n"
	"        if (self::STATUS_STARTED !== $this->status) {\n"
	"            return;\n"
	"        }\n"
	"\n"
	"        $this->processInformation = proc_get_status($this->process);\n"
	"        $this->captureExitCode();\n"
	"\n"
	"        $this->readPipes($blocking, \'\\\\\' === DS ? !$this->processInformation[\'running\'] : true);\n"
	"\n"
	"        if (!$this->processInformation[\'running\']) {\n"
	"            $this->close();\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 是否开启 \'--enable-sigchild\'\n"
	"     * @return bool\n"
	"     */\n"
	"    protected function isSigchildEnabled()\n"
	"{\n"
	"        if (null !== self::$sigchild) {\n"
	"            return self::$sigchild;\n"
	"        }\n"
	"\n"
	"        if (!function_exists(\'phpinfo\')) {\n"
	"            return self::$sigchild = false;\n"
	"        }\n"
	"\n"
	"        ob_start();\n"
	"        phpinfo(INFO_GENERAL);\n"
	"\n"
	"        return self::$sigchild = false !== strpos(ob_get_clean(), \'--enable-sigchild\');\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 验证是否超时\n"
	"     * @param int|float|null $timeout\n"
	"     * @return float|null\n"
	"     */\n"
	"    private function validateTimeout($timeout)\n"
	"{\n"
	"        $timeout = (float) $timeout;\n"
	"\n"
	"        if (0.0 === $timeout) {\n"
	"            $timeout = null;\n"
	"        } elseif ($timeout < 0) {\n"
	"            throw new \\InvalidArgumentException(\'The timeout value must be a valid positive integer or float number.\');\n"
	"        }\n"
	"\n"
	"        return $timeout;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 读取pipes\n"
	"     * @param bool $blocking\n"
	"     * @param bool $close\n"
	"     */\n"
	"    private function readPipes($blocking, $close)\n"
	"{\n"
	"        $result = $this->processPipes->readAndWrite($blocking, $close);\n"
	"\n"
	"        $callback = $this->callback;\n"
	"        foreach ($result as $type => $data) {\n"
	"            if (3 == $type) {\n"
	"                $this->fallbackExitcode = (int) $data;\n"
	"            } else {\n"
	"                $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);\n"
	"            }\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 捕获退出码\n"
	"     */\n"
	"    private function captureExitCode()\n"
	"{\n"
	"        if (isset($this->processInformation[\'exitcode\']) && -1 != $this->processInformation[\'exitcode\']) {\n"
	"            $this->exitcode = $this->processInformation[\'exitcode\'];\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 关闭资源\n"
	"     * @return int 退出码\n"
	"     */\n"
	"    private function close()\n"
	"{\n"
	"        $this->processPipes->close();\n"
	"        if (is_resource($this->process)) {\n"
	"            $exitcode = proc_close($this->process);\n"
	"        } else {\n"
	"            $exitcode = -1;\n"
	"        }\n"
	"\n"
	"        $this->exitcode = -1 !== $exitcode ? $exitcode : (null !== $this->exitcode ? $this->exitcode : -1);\n"
	"        $this->status   = self::STATUS_TERMINATED;\n"
	"\n"
	"        if (-1 === $this->exitcode && null !== $this->fallbackExitcode) {\n"
	"            $this->exitcode = $this->fallbackExitcode;\n"
	"        } elseif (-1 === $this->exitcode && $this->processInformation[\'signaled\']\n"
	"            && 0 < $this->processInformation[\'termsig\']\n"
	"        ) {\n"
	"            $this->exitcode = 128 + $this->processInformation[\'termsig\'];\n"
	"        }\n"
	"\n"
	"        return $this->exitcode;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 重置数据\n"
	"     */\n"
	"    private function resetProcessData()\n"
	"{\n"
	"        $this->starttime                    = null;\n"
	"        $this->callback                     = null;\n"
	"        $this->exitcode                     = null;\n"
	"        $this->fallbackExitcode             = null;\n"
	"        $this->processInformation           = null;\n"
	"        $this->stdout                       = null;\n"
	"        $this->stderr                       = null;\n"
	"        $this->process                      = null;\n"
	"        $this->latestSignal                 = null;\n"
	"        $this->status                       = self::STATUS_READY;\n"
	"        $this->incrementalOutputOffset      = 0;\n"
	"        $this->incrementalErrorOutputOffset = 0;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 将一个 POSIX 信号发送到进程中。\n"
	"     * @param int  $signal\n"
	"     * @param bool $throwException\n"
	"     * @return bool\n"
	"     */\n"
	"    private function doSignal($signal, $throwException)\n"
	"{\n"
	"        if (!$this->isRunning()) {\n"
	"            if ($throwException) {\n"
	"                throw new \\LogicException(\'Can not send signal on a non running process.\');\n"
	"            }\n"
	"\n"
	"            return false;\n"
	"        }\n"
	"\n"
	"        if ($this->isSigchildEnabled()) {\n"
	"            if ($throwException) {\n"
	"                throw new \\RuntimeException(\'This PHP has been compiled with --enable-sigchild. The process can not be signaled.\');\n"
	"            }\n"
	"\n"
	"            return false;\n"
	"        }\n"
	"\n"
	"        if (true !== @proc_terminate($this->process, $signal)) {\n"
	"            if ($throwException) {\n"
	"                throw new \\RuntimeException(sprintf(\'Error while sending signal `%s`.\', $signal));\n"
	"            }\n"
	"\n"
	"            return false;\n"
	"        }\n"
	"\n"
	"        $this->latestSignal = $signal;\n"
	"\n"
	"        return true;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 确保进程已经开启\n"
	"     * @param string $functionName\n"
	"     */\n"
	"    private function requireProcessIsStarted($functionName)\n"
	"{\n"
	"        if (!$this->isStarted()) {\n"
	"            throw new \\LogicException(sprintf(\'Process must be started before calling %s.\', $functionName));\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 确保进程已经终止\n"
	"     * @param string $functionName\n"
	"     */\n"
	"    private function requireProcessIsTerminated($functionName)\n"
	"{\n"
	"        if (!$this->isTerminated()) {\n"
	"            throw new \\LogicException(sprintf(\'Process must be terminated before calling %s.\', $functionName));\n"
	"        }\n"
	"    }\n"
	"}\n"
	"\n"
;
#endif